﻿#include "DownloadTool.h"
#include "MainWindow.h"
#include "ui_MainWindow.h"

#include <QProcess>
#include <QCoreApplication>
#include <QDebug>
#include <QtConcurrent>

#include "MachineHelper.h"

MainWindow::MainWindow(const QString& downloadUrl, const bool& foreFlag, const QString& titleContext,
                       const bool& externalNetworkFlag, const QString& quictunPort, const QString& serverAppAddr,
                       QWidget* parent)
    : BaseDialog(parent),
      ui(new Ui::MainWindow),
      m_downloadUrl(downloadUrl),
      mQuictunPort(quictunPort),
      mServerAppAddr(serverAppAddr),
      titleContext_(titleContext)
{
    ui->setupUi(this);

    ui->label_2->setText(titleContext);
    //使用 HTML 富文本，实现图文混排
    // ui->label_2->setText(
    //     QString(R"(<p style="vertical-align: middle;">
    //               <img src=":/images/product.png" width="40" height="40"
    //                    style="vertical-align: middle; margin-right: 5px;">
    //               %1
    //            </p>)")
    //         .arg(titleContext));

    ui->pushButtonInstall->setText(tr("install"));
    ui->upgradeDialogCloseButton->setEnabled(true);
    ui->pushButtonInstall->setEnabled(true);
    setWindowFlag(Qt::WindowStaysOnTopHint);
    setPageType(ProgressBarPage);

    mForeFlag = foreFlag;
    qDebug() << "mForeFlag_________________" << mForeFlag;
    if (!externalNetworkFlag) {
        qDebug() << "MainWindow,not use quictun, externalNetworkFlag: " << externalNetworkFlag;
        m_downloadTool = new DownloadTool(downloadUrl, "", this);
        connect(m_downloadTool, SIGNAL(sigProgress(qint64, qint64, qreal)), this,
                SLOT(onUpdateProgressBar(qint64, qint64, qreal)));
        connect(m_downloadTool, SIGNAL(sigDownloadFinished()), this, SLOT(onDownloadFinished()));
        connect(m_downloadTool, &DownloadTool::sigDownloadFailed, this, &MainWindow::onDownloadFailed);

        m_downloadTool->startDownload();
    } else {
        qDebug() << "MainWindow(), use quictun,externalNetworkFlag: " << externalNetworkFlag;
        mNetworkQuictunHelper = NetworkQuictunHelper::instance();
        connect(mNetworkQuictunHelper, &NetworkQuictunHelper::signalPlatFormTunnel, this,
                &MainWindow::onPlatFormTunnel);
        CreateTunnelRequest request;
        request.mGatewayAddr   = mQuictunPort;
        request.mServerAppAddr = mServerAppAddr;
        mNetworkQuictunHelper->sendPostCreateTunnel(request);
    }
    connect(ui->pushButtonInstall, &QPushButton::clicked, this, &MainWindow::onStartInstall);
    connect(ui->upgradeDialogCloseButton, &QPushButton::clicked, this, &MainWindow::close);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::setPageType(PageType pageType)
{
    ui->stackedWidgetMain->setCurrentIndex(pageType);
}

void MainWindow::onUpdateProgressBar(qint64, qint64, qreal progress)
{
    ui->progressBar->setValue(progress * 100);
    ui->progressBar->update();
    ui->labelProgressValue->setText(QString::number(progress * 100, 'f', 2) + QLatin1Char('%'));
}

void MainWindow::onDownloadFinished()
{
    if (mForeFlag) {
        onStartInstall();
    } else {
        setPageType(InstallPage);
    }
}

void MainWindow::onDownloadFailed()
{
    ui->labelProgressValue->setText("-");

    static QRandomGenerator randomGenerator;
    static QTimer           timer;
    static int              retryCount = 0;  // 添加重试次数
    timer.setSingleShot(true);
    if (!timer.isActive()) {
        int interval = randomGenerator.bounded(20000, 40000);
        timer.setInterval(interval);
        // 间隔时间内，重试三次未下载成功，退出升级
        timer.callOnTimeout(this, [=]() {
            if (!m_downloadTool->getDownloadSuccessFlag()) {
                if (retryCount < 3) {
                    m_downloadTool->startDownload();
                    retryCount++;
                    qDebug() << "QTimer::singleShot, startRequest:" << m_downloadTool->getgetDownloadUrl()
                             << " ,m_httpSuccessed:" << m_downloadTool->getDownloadSuccessFlag()
                             << ",interval:" << interval << ",retryCount:" << retryCount;
                } else {
                    qDebug() << "## Maximum retry count reached, exiting program.";
                    retryCount = 0;
                    QCoreApplication::exit(1);
                }
            } else {
                retryCount = 0;
                qDebug() << "##Download successful. m_httpSuccessed:" << m_downloadTool->getDownloadSuccessFlag()
                         << ", retryCount: " << retryCount;
            }
        });
        timer.start();
    }
}

void MainWindow::onPlatFormTunnel(CreateTunnelReply reply)
{
    QString                 input;
    QRegularExpression      regex("\\d+\\.\\d+\\.\\d+\\.\\d+:\\d+");

    QRegularExpressionMatch match = regex.match(m_downloadUrl);

    if (match.hasMatch()) {
        input = match.captured(0);
    }
    m_downloadUrl.replace(input, reply.mLocalSocketAddr);

    m_downloadTool = new DownloadTool(m_downloadUrl, "", this);
    connect(m_downloadTool, SIGNAL(sigProgress(qint64, qint64, qreal)), this,
            SLOT(onUpdateProgressBar(qint64, qint64, qreal)));
    connect(m_downloadTool, SIGNAL(sigDownloadFinished()), this, SLOT(onDownloadFinished()));
    connect(m_downloadTool, &DownloadTool::sigDownloadFailed, this, &MainWindow::onDownloadFailed);
    m_downloadTool->startDownload();
}

bool MainWindow::executeCommand(const QString& command, int maxRetries)
{
    QProcess process;
    process.start(command);

    // 设置超时2分钟
    if (!process.waitForFinished(12000)) {
        qDebug() << "Process timed out: " << command;
        return false;
    }

    if (process.exitCode() != 0) {
        qDebug() << "Process failed with exit code:" << process.exitCode()
                 << "\nError:" << QString::fromStdString(process.readAllStandardError().toStdString())
                 << "\nOutput:" << QString::fromStdString(process.readAllStandardOutput().toStdString());

        if (maxRetries > 0) {
            return executeCommand(command, maxRetries - 1);
        } else {
            return false;
        }
    }
    qDebug() << "Process succeeded: " << command;
    return true;
}

void MainWindow::onStartInstall()
{
    static bool alreadyStarted = false;
    if (alreadyStarted) return;

    if (mForeFlag) {
        setPageType(InstallPage);
        ui->horizontalLayout_3->setEnabled(false);
        //ui->label_3->setVisible(true);
        ui->label_4->setVisible(true);
        ui->pushButtonInstall->setText(tr("installing"));
        ui->upgradeDialogCloseButton->setEnabled(false);
        ui->pushButtonInstall->setEnabled(false);

    } else {
        ui->pushButtonInstall->setText(tr("installing"));
        ui->upgradeDialogCloseButton->setEnabled(false);
        ui->pushButtonInstall->setEnabled(false);
    }

    QString executePath = m_downloadTool->getFileName();
    qDebug() << "onStartInstall" << executePath;
#ifdef Q_OS_WIN
    QStringList arguments;
    arguments << "/S" << QStringLiteral("/D=%1").arg(QDir::toNativeSeparators(qApp->applicationDirPath()));

    qDebug() << "Arguments: " << arguments;
    alreadyStarted = QProcess::startDetached(executePath, arguments);
#else
    QFutureWatcher<void> watcher;
    QEventLoop           loop;
    QObject::connect(&watcher, &QFutureWatcher<void>::finished, &loop, &QEventLoop::quit);

    auto feature = QtConcurrent::run([this, executePath]() {
        bool                AdministratorAccount = false;
        QProcessEnvironment env                  = QProcessEnvironment::systemEnvironment();

        // 获取用户名称
        QString username = env.value("USER");

        if (!username.isEmpty()) {
            if (username == "root") AdministratorAccount = true;
        }
        if (AdministratorAccount) {
            QString path = QString("dpkg -i %1").arg(executePath);
            if (!executeCommand(path, 2)) {
                qDebug() << "username: " << username
                         << " is AdministratorAccount, Failed to execute command after 2 retries";
                qApp->exit(-1);
            }
        } else {
            QString commandstring =
                (QStringList() << "sudo" << "pkexec" << "env" << "DISPLAY=:0" << "dpkg" << "-i" << executePath)
                    .join(" ");
            qDebug() << "Process ready start, command: " << commandstring;

            if (!executeCommand(commandstring, 2)) {
                qDebug() << "username: " << username << ", Failed to execute command after 2 retries";
                qApp->exit(-1);
            }
        }

        // run vvclass
        QString strSubstr = titleContext_.section("-", 0, 0);
        qDebug() << "substr: " << strSubstr;
        if (strSubstr.compare("VVClass") == 0) {
            bool success = QProcess::startDetached("/opt/apps/VVClass/bin/VVClass.sh");
            if (success) {
                qDebug() << "VVClass, script started sucessfully. ret:" << success;
            }
        }
    });
    watcher.setFuture(feature);
    loop.exec();

#endif
    qApp->exit(0);
}
